

/*
 * @Author       : DonnieLiang
 * @Date         : 2024-11-11
 * @Version      : 1.0
 * @Description  : tcp_client_app
 */




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include <memory.h> /*使用memcpy所需的头文件*/

#include <time.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>


//#include <pthread.h>  

//#include "proto_plat.h"

#include "gw_ktj_tcp_client.h"
#include "iotv30_tcp_client.h"
#include "uart_printf.h"
#include "rtc_calendar.h"
#include "tcp_api_01.h" 


 ClientInfo_st  ClientInfo[TCP_API_CH_MAX];

 Tcp_TxData_st  Tcp_TxData[TCP_API_CH_MAX];
 Tcp_RxData_st  Tcp_RxData[TCP_API_CH_MAX];


static const tcp_api_obj_st tcp_api_obj[TCP_API_CH_MAX]={
    {iotv30_TCP_Reset,iotv30_IsTcpClientConnected}, 
    {gw_ktj_TCP_Reset,gw_ktj_IsTcpClientConnected}

};



void Tcp_API_Init(void)
{
uint8_t ch;	
	
	for( ch=0;ch< TCP_API_CH_MAX;ch++)
    {
        memset((uint8_t*)&Tcp_TxData[ch],0,sizeof(Tcp_TxData_st) );
        memset((uint8_t*)&Tcp_RxData[ch],0,sizeof(Tcp_RxData_st) );

        memset(&ClientInfo[ch] , 0, sizeof(ClientInfo_st));
        ClientInfo[ch].fd = -1;
        ClientInfo[ch].addr.sin_family   = AF_INET;
    }


//    Tcp_TxData[ch].Flag	= 0;	
//    Tcp_TxData[ch].Len	= 0;
	
}




//需要增加判断socket链接是否正常，

//返回值 0---发送失败，1---发送成功
uint8_t TCP_API_Send(uint8_t ch, uint8_t* data,uint16_t len )
{
	RTC_Prinft_Now( );
    LOG_NAME();

    if( NULL==data )
	{
   	   printf("NULL==data point error\n");
	   return 0; 
	}

    if( ch >=TCP_API_CH_MAX)
	{
   	   printf("ch=%d error\n",ch);
	   return 0; 
	}
    
    if( !tcp_api_obj[ch].IsTcpClientConnected() )
	{
   	   printf("TcpClient[%d] Connect close,TCP send abort\n",ch);
	   return 0; 
	}

	if( len>=TCP_CLIENT_TX_BUFSIZE )
	{
	   printf("error: data len outof TCP_CLIENT_TX_BUFSIZE\n");
	   return 0;
	}else{

        printf("Tcp_TxData[%d].Buff=%p,pdata=%p,len= %d\n",ch,Tcp_TxData[ch].Buff,data,len);////这里buf=cb9f5c05,data=0x3fcb429898,len= 65
       if( TCP_API_CH_IOTV30==ch)
       {
           printf("Tcp_Tx_ch=%d, ch_iotv30\n",ch);
           UartPrintHex2String(data,len );
        // UartPrintHex2String_NoSpace(data,len );         
       }  else if( TCP_API_CH_LOCAL==ch)
       {
          printf("Tcp_Tx_ch=%d, local_ktj_js\n",ch);
          printf("%s\n",data);
       }

     
		memcpy(Tcp_TxData[ch].Buff, data,len );
		Tcp_TxData[ch].Flag = 1;

        if( TCP_API_CH_LOCAL==ch)
        {
          Tcp_TxData[ch].Buff[len++] = '\n';  //结尾手动添加结束符	
        }
    
        Tcp_TxData[ch].Len = len;	

		printf("Tcp_ch%d_TxData copy done\n",ch );

       return 1;		
	}
	

}







//返回值 0---发送失败，1---发送成功
uint8_t TCP_API_Send_Now(uint8_t ch, uint8_t* data,uint16_t len )
{
uint16_t ret;
//char enter_code='\n';

	RTC_Prinft_Now( );
    LOG_NAME();

    if( NULL==data )
	{
   	   printf("NULL==data error\n");
	   return 0; 
	}


    if( ch >=TCP_API_CH_MAX)
	{
   	   printf("ch=%d error\n",ch);
	   return 0; 
	}
    
    if( !tcp_api_obj[ch].IsTcpClientConnected() )
	{
   	   printf("TcpClient[%d] Connect close,TCP send now abort\n",ch);
	   return 0; 
	}



	if( len>=TCP_CLIENT_TX_BUFSIZE )
	{
	   printf("error: data len outof TCP_CLIENT_TX_BUFSIZE\n");
	   return 0;
	}


    //发送数据，最后一个参数为 0 时，可以用 write() 替代（ send 等同于 write ）						
    //write(ClientInfo[ch].fd, Tcp_TxData[TCP_API_CH_IOTV30].Buff , Tcp_TxData[TCP_API_CH_IOTV30].Len );	

    if( TCP_API_CH_LOCAL==ch)
    {
      // ret = send(ClientInfo[ch].fd, data, len , 0 );
       // send(ClientInfo[ch].fd, (uint8_t*)&enter_code, 1 , 0 ); /////ver.1.40-----不知道搞什么飞机，需要加回车结束------分包发送--车工没办法解决-------

       memcpy(Tcp_TxData[ch].Buff, data,len );

       Tcp_TxData[ch].Buff[len++] = '\n' ;   //json协议需要在末尾添加回车 
       ret = send(ClientInfo[ch].fd, Tcp_TxData[ch].Buff, len , 0 );

    }else{
       ret = send(ClientInfo[ch].fd, data, len , 0 );

    }


    printf("Tcp_TxData[%d].Buff=%p,pdata=%p,len= %d\n",ch,Tcp_TxData[ch].Buff,data,len );    ////这里buf=cb9f5c05,data=0x3fcb429898,len= 65
    if( TCP_API_CH_IOTV30==ch)  
    {
        printf("Tcp_Tx_ch=%d, ch_iotv30\n",ch);
     // UartPrintHex2String(data,len );
        UartPrintHex2String_NoSpace(data,len );         
    }  else if( TCP_API_CH_LOCAL==ch)
    {
        printf("Tcp_Tx_ch=%d, local_ktj_js\n",ch);
        printf("%s\n",Tcp_TxData[ch].Buff);
    }else{
        printf("error: unkonw tcp channel\n");       
    }


    if ( ret != len )
    {
        printf("iotv30 server offline ret=%d,len=%d\n\r",ret,len);   // //---这里报错----????-------------------------      
         close(ClientInfo[ch].fd );
         tcp_api_obj[ch].tcp_reset();
        // ucTcp_ClientStep = 0; //重新建立链接	
        return 0;	
    }else{
        printf("iotv30  socket send done\n\r");
        return 1;	       
    }

}


















/**
 * @Descripttion: 链接TCP服务器
 * @param {char*} ip: TCP服务器IP
 * @param {char} *port： TCP服务器端口
 * @return {int}： 建立成功后socket套接字
 */
int tcp_connect(const char *ip, const char *port)
{
    int ret = -1;
    // step1: creat socket
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);//创建socket
    if (socket_fd <= 0)
    {
        printf("creat socket faild, socket_fd: %d\n\r", socket_fd);
        return -1;
    }
    // step2: connect tcp service
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(ip); //服务端地址
    serv_addr.sin_port = htons(atoi(port));

		
	printf("ip: %s, port: %s\n\r", ip, port );		
		
    ret = connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //连接服务端

    if (0 != ret)
    {
       // printf("tcp_connect faild, ret: %d\n\r", ret);   //打印过于频繁
        close(socket_fd);
        return -2;
    }

    return socket_fd;
}


  /**
  * @Descripttion: 链接TCP服务器
  * @param {char*} ip: TCP服务器IP
  * @param {char} *port： TCP服务器端口
  * @return {int}： 建立成功后socket套接字
  */
 int tcp_client_connect(ClientInfo_st* pinfo)
 {

 int socket_fd;

	 // step1: creat socket

//	  socket_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);//创建socket
	  socket_fd = socket(AF_INET, SOCK_STREAM, 0);//创建socket       测试过ok 

	 if ( socket_fd <= 0)
	 {
		 printf("creat socket faild, socket_fd: %d\n\r", socket_fd);
		 return -1;  //创建socket 失败
	 }

     if ( set_socket_keepalive(socket_fd) != 0 )
     {
        printf("set socket keepalive faild, socket_fd: %d\n\r", socket_fd);
        close( socket_fd );
        return -1;  //设置socket 失败
     }

	 
	 // step2: connect tcp service	 
		 
	 if ( connect( socket_fd , (struct sockaddr *)& (pinfo->addr) , sizeof( pinfo->addr ) ) <0 )  //连接服务端  struct sockaddr_in 
	 {
		// printf("tcp_connect faild\n\r");   //打印过于频繁
		 close( socket_fd );
		 return -2;  //连接服务器失败
	 }

	 pinfo->fd =  socket_fd ;
 
	 return socket_fd;
 }


/**
   @brief 设置socket保活探测器
   @note  解决socket连接因网络异常断开而变成CLOSE_WAIT无法释放的问题
*/ 
int set_socket_keepalive(int sockfd)
{
    int keepalive = 1;     // keepalive enable
    int keepidle = 60;     // tcp_keepalive_time 60 second
    int keepinterval = 10; // tcp_keepalive_intvl 10 second
    int keepcount = 3;     // tcp_keepalive_probes 3 count
    if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive))!=0){
        perror("SO_KEEPALIVE");
        close(sockfd);
        return -1;
    }
    if (setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle))!=0){
        perror("TCP_KEEPIDLE");
        close(sockfd);
        return -1;
    }
    if (setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval))!=0){
        perror("TCP_KEEPINTVL");
        close(sockfd);
        return -1;
    }
    if (setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount))!=0){
        perror("TCP_KEEPCNT");
        close(sockfd);
        return -1;
    }
    return 0;
}



















